package com.roger.springcloudGreenwich.service;

import com.roger.springcloudGreenwich.entity.GatewayRoute;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
 * Created by admin on 2020/1/14.
 */
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    private ApplicationEventPublisher publisher;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private final static String SQL = "select * from gateway_route";

    //增加路由
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

    //更新路由
    public String update(RouteDefinition definition) {
        try {
            this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
        } catch (Exception e) {
            return "update fail,not find route routeId: "+definition.getId();
        }
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        } catch (Exception e) {
            return "update route fail";
        }
    }

    //删除路由
    public Mono<ResponseEntity<Object>> delete(String id) {
        return this.routeDefinitionWriter.delete(Mono.just(id))
                .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
                .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));
    }

    public List<GatewayRoute> selectGatewayRoute(){
        List<GatewayRoute> gatewayRouteList = jdbcTemplate.query(SQL,new BeanPropertyRowMapper<>(GatewayRoute.class));
        return gatewayRouteList;
    }

    public Object reload() throws URISyntaxException {
        List<GatewayRoute> gatewayRouteList = this.selectGatewayRoute();
        for(GatewayRoute route : gatewayRouteList){
            delete(route.getId());
        }
        for(GatewayRoute route : gatewayRouteList){
            RouteDefinition routeDefinition = new RouteDefinition();
            routeDefinition.setId(route.getId());
            List<PredicateDefinition> predicates=new ArrayList<>();
            PredicateDefinition definition=new PredicateDefinition();
            //注意name
            definition.setName("Path");
            definition.addArg("pattern",route.getPredicates());
            predicates.add(definition);
            routeDefinition.setPredicates(predicates);

            List<FilterDefinition> filters =new ArrayList<>();
            FilterDefinition filterDefinition = new FilterDefinition();

            //这里暂时只支持注册中心
            URI uri = new URI("lb://" + route.getUri());
            routeDefinition.setUri(uri);
            routeDefinition.setOrder(route.getOrder());
            String save = add(routeDefinition);
            System.out.println(save);
        }

        return "success";
    }


    public Object loadRouteConfig(){
        //从数据库拿到路由配置
        List<GatewayRoute> gatewayRouteList = this.selectGatewayRoute();
        gatewayRouteList.forEach(gatewayRoute -> {
            RouteDefinition definition = new RouteDefinition();
            Map<String, String> predicateParams = new HashMap<>(8);
            PredicateDefinition predicate = new PredicateDefinition();
            FilterDefinition filterDefinition = new FilterDefinition();
            Map<String, String> filterParams = new HashMap<>(8);

            URI uri = null;
            if(gatewayRoute.getUri().startsWith("http")){
                //http地址
                uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();
            }else{
                //注册中心
                uri = UriComponentsBuilder.fromUriString("lb://"+gatewayRoute.getUri()).build().toUri();
            }

            definition.setId(gatewayRoute.getId().toString());
            // 名称是固定的，spring gateway会根据名称找对应的PredicateFactory
            predicate.setName("Path");
            predicateParams.put("pattern",gatewayRoute.getPredicates());
            predicate.setArgs(predicateParams);

            // 名称是固定的, 路径去前缀
            //TO_DO
            /*
            filterDefinition.setName("StripPrefix");
            filterParams.put("_genkey_0", gatewayRoute.getFilters().toString());
            filterDefinition.setArgs(filterParams);
            */

            definition.setPredicates(Arrays.asList(predicate));
            definition.setFilters(Arrays.asList(filterDefinition));
            definition.setUri(uri);
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        });

        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }


    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}
